#include "net/CTSocket.h"
#include "CSMsgDef.h"
#include "PBMsgHead.pb.h"
#include "MsgGM.pb.h"
#include "commmsg.h"
#include "CTBuffer.h"
#include "CTArray.h"
#include "CTSizeString.h"
#include "net/CTBinhex.h"

#include "MsgComm.pb.h"
#include "MsgDrug.pb.h"
#include "MsgMoveTo.pb.h"
#include "MsgBattle.pb.h"
#include "MsgPartner.pb.h"
#include "MsgTreasure.pb.h"
#include "MsgWorldBoss.pb.h"
#include "MsgAcademyBoss.pb.h"

using namespace CTLib;

#define SVR_VERSION     1000
#define BUFF_LENGTH     10240
#define ROLENAME_LEN     20

int ReqToName(MsgReqGMPlayer& stReq, int argc, char* argv[])
{
    //进入函数 要求argc >= 4 参数1:27 参数2:GID 参数3:大命令
    //内部命令:./gm 27 GID Cmd SubCmd ...

    unsigned int uiGID = (unsigned int)atoi(argv[2]);//参数2:GID
    int iCmd = atoi(argv[3]);//参数3:大命令

    int iMsgByteSize = 0;
    CTBuffer stBufBin;
    stBufBin.Attach(NULL, BUFF_LENGTH, 0);
    CTSizeString<BUFF_LENGTH> szBufHex;

    stBufBin.Clear();

    stReq.set_sub_type(ID_GM_PLAYER_SUB_SEND_INNER_CMD);//27
    stReq.set_gid((int)uiGID);//GID
    stReq.add_datas(iCmd);//Cmd

    switch (iCmd)
    {
    case ID_MAIN_MAP_MOVE://1009
        {
            MsgReqMoveTo stMoveReq;
            if (argc < 7) {return -1;}

            stMoveReq.set_gid((int)uiGID);

            stMoveReq.set_map_id(atoi(argv[4]));//参数4:地图ID
            stMoveReq.set_pos_x(atoi(argv[5]));//参数5:x坐标
            stMoveReq.set_pos_y(atoi(argv[6]));//参数6:y坐标

            iMsgByteSize = stMoveReq.ByteSize();
            stMoveReq.SerializeToArray((void*)stBufBin.GetFreeBuf(),
                iMsgByteSize);
            stBufBin.Append(iMsgByteSize);

        }
        break;
    case ID_MAIN_WORLD_BOSS://1089
        {
            MsgReqWorldBoss stWBReq;
            if (argc < 5) {return -1;}
            int iSubType = atoi(argv[4]);//参数4:子命令

            stWBReq.set_gid((int)uiGID);
            stWBReq.set_sub_type(iSubType);

            if (3 == iSubType && argc >= 8)
            {
                MsgBattleExtInfo* pstExtInfo =
                    stWBReq.mutable_battle_ext_info();
                pstExtInfo->set_map_id(atoi(argv[5]));//参数5:地图ID
                pstExtInfo->set_pos_x(atoi(argv[6]));//参数6:x坐标
                pstExtInfo->set_pos_y(atoi(argv[7]));//参数7:y坐标
            }

            iMsgByteSize = stWBReq.ByteSize();
            stWBReq.SerializeToArray((void*)stBufBin.GetFreeBuf(),
                iMsgByteSize);
            stBufBin.Append(iMsgByteSize);

        }
        break;
    case ID_MAIN_ACADEMY_BOSS://1093
        {
            MsgReqAcademyBoss stABReq;
            if (argc < 6) {return -1;}
            int iSubType = atoi(argv[4]);//参数4:子命令
            int iAcademyType = atoi(argv[5]);//参数5:学院类型

            stABReq.set_gid((int)uiGID);
            stABReq.set_sub_type(iSubType);
            stABReq.set_academy_type(iAcademyType);

            if (3 == iSubType && argc >= 10)
            {
                stABReq.set_monster_type(atoi(argv[6]));//参数6: 怪物类型:1 左侍从 2 右侍从 3 试练使者

                MsgBattleExtInfo* pstExtInfo =
                    stABReq.mutable_battle_ext_info();
                pstExtInfo->set_map_id(atoi(argv[7]));//参数7:地图ID
                pstExtInfo->set_pos_x(atoi(argv[8]));//参数8:x坐标
                pstExtInfo->set_pos_y(atoi(argv[9]));//参数9:y坐标
            }

            iMsgByteSize = stABReq.ByteSize();
            stABReq.SerializeToArray((void*)stBufBin.GetFreeBuf(),
                iMsgByteSize);
            stBufBin.Append(iMsgByteSize);

        }
        break;
    case ID_MAIN_PARTNER://1021
        {
            MsgReqPartner stPartnerReq;
            if (argc < 6) {return -1;}
            int iSubType = atoi(argv[4]);//参数4:子命令
            int iResID = atoi(argv[5]);//参数5:伙伴ID

            stPartnerReq.set_gid((int)uiGID);
            stPartnerReq.set_sub_type(iSubType);
            stPartnerReq.set_res_id(iResID);

            iMsgByteSize = stPartnerReq.ByteSize();
            stPartnerReq.SerializeToArray((void*)stBufBin.GetFreeBuf(),
                iMsgByteSize);
            stBufBin.Append(iMsgByteSize);

        }
        break;
    case ID_MAIN_TREASURE://1169
        {
            MsgReqTreasure stTreasureReq;
            if (argc < 6) {return -1;}
            int iSubType = atoi(argv[4]);//参数4:子命令
            int iResID = atoi(argv[5]);//参数5:秘宝ID

            stTreasureReq.set_gid((int)uiGID);
            stTreasureReq.set_sub_type(iSubType);
            stTreasureReq.set_treasure_id(iResID);

            iMsgByteSize = stTreasureReq.ByteSize();
            stTreasureReq.SerializeToArray((void*)stBufBin.GetFreeBuf(),
                iMsgByteSize);
            stBufBin.Append(iMsgByteSize);

        }
        break;
    case ID_MAIN_MAKE_DRUG://1125
        {
            MsgReqDrugMake stDrugMakeReq;
            if (argc < 8) {return -1;}
            int iOpt = atoi(argv[4]);//参数4:子操作
            int iRoleID = atoi(argv[5]);//参数5:操作个体ID[0:主角 伙伴配置ID:伙伴]
            int iDrugID = atoi(argv[6]);//参数6:魔药ID[1~32]
            int iMakeType = atoi(argv[7]);//参数7:制作方式[2:使用金币]

            stDrugMakeReq.set_gid((int)uiGID);
            stDrugMakeReq.set_opt(iOpt);
            stDrugMakeReq.set_role_id(iRoleID);
            stDrugMakeReq.set_drug_id(iDrugID);
            stDrugMakeReq.set_method(iMakeType);

            iMsgByteSize = stDrugMakeReq.ByteSize();
            stDrugMakeReq.SerializeToArray((void*)stBufBin.GetFreeBuf(),
                iMsgByteSize);
            stBufBin.Append(iMsgByteSize);

        }
        break;
    case ID_MAIN_MAGIC_DOOR://1213 //魔界传送门
        {}
        break;
    default:
        //进入函数 要求argc >= 4 参数1:27 参数2:GID 参数3:大命令
        return -1;
    }

    CTBinhex::Encode((const char*)stBufBin.GetUsedBuf(), stBufBin.GetUsedLen(),
        (char*)(szBufHex()));

    stReq.set_name(szBufHex());

    return 0;
}

//通用参数 增加新的操作时候 这里的请求包一般不需要处理
int DoReqHeadBody(PBMsgHead& Msghead, MsgReqGMPlayer& stReq,
                  int argc, char* argv[])
{
    Msghead.set_version(SVR_VERSION);
    Msghead.set_time((int)time(NULL));
    Msghead.set_msgact(0);
    Msghead.set_msgret(0);
    Msghead.set_msgtype(CSMsgDef::EMT_REQUEST);
    Msghead.set_msgid(ID_MAIN_GM_PLAYER);

    int iSubCmd = ID_GM_PLAYER_SUB_GET_HELP;

    if (argc >= 6 && ID_GM_PLAYER_SUB_SEND_INNER_CMD == atoi(argv[3]))
    { 
        return ReqToName(stReq, argc, argv);
    }

    if (argc >= 5)
    {
        iSubCmd = (int)atoi(argv[3]);
        if (ID_GM_PLAYER_SUB_INFO_TOKEN == iSubCmd)
        {
            stReq.set_name(argv[4]);
        }
        else
        {
            stReq.set_gid((unsigned int)atoi(argv[4]));
        }
        
        for (int i = 5; i < argc; ++i)
        {
            stReq.add_datas(atoi(argv[i]));
        }
    }

    stReq.set_sub_type(iSubCmd);

    return 0;
}

int Encode(PBMsgHead& Msghead, MsgReqGMPlayer& stReq,
           char* buff, int& iDataLength)
{
    int iMsgHeadLen = Msghead.ByteSize();
    *(int*)(buff + sizeof(int)) = (int)htonl((int)iMsgHeadLen);
    Msghead.SerializeToArray((void*)(buff + sizeof(int) + sizeof(int)),
                             Msghead.ByteSize());

    int iMsgBodyLen = stReq.ByteSize();
    *(int*)(buff + sizeof(int) + sizeof(int) + iMsgHeadLen) =
        (int)htonl((int)iMsgBodyLen);
    stReq.SerializeToArray((void*)(buff + sizeof(int) + sizeof(int) +
                           iMsgHeadLen + sizeof(int)), stReq.ByteSize());

    *(char*)(buff + sizeof(int)*3 + iMsgHeadLen + iMsgBodyLen) = '\t';
    iDataLength = sizeof(int)*3 + iMsgHeadLen + iMsgBodyLen + sizeof(char);

    *(int*)(buff) = (int)htonl((int)iDataLength);
    return 0;
}

int Decode(PBMsgHead& Msghead, MsgAnsGMPlayer& stAns,
           char* buff, int& iDataLength)
{
    int iMsgTotalLen = ntohl(*(int*)buff);
    int iMsgHeadLen = ntohl(*(int*)(buff+sizeof(int)));
    int iMsgBodyLen = ntohl(*(int*)(buff+sizeof(int)+sizeof(int)+iMsgHeadLen));
    if (iMsgTotalLen <= 0)
    {
        printf("msglen error(%d)!\n",iMsgTotalLen);
        return -1;
    }
    if (buff[iMsgTotalLen - 1] != '\t')
    {
        printf("flag error(%d)!\n",buff[iMsgTotalLen - 1]);
        return -1;
    }
    
    Msghead.ParseFromArray((void*)(buff+sizeof(int)+sizeof(int)), iMsgHeadLen);

    stAns.ParseFromArray((void*)(buff + sizeof(int) + sizeof(int) +
                         iMsgHeadLen + sizeof(int)), iMsgBodyLen);

    return 0;
}

int OutputMsg(PBMsgHead& Msghead, MsgAnsGMPlayer& stAns)
{
    printf("[版本(%d) 时间(%d) 透传(%d) 主命令(%d) 子命令(%d) 返回码(%d)]\n", 
            Msghead.version(),Msghead.time(),Msghead.msgact(),Msghead.msgid(),
            stAns.sub_type(),Msghead.msgret());

    if (stAns.has_name())
    {
        printf("%s\n",stAns.name().c_str());
    }

    return 0;
}

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        return 0;
    }

    int iRet = 0;
    CTSocket sSocket;
    iRet = sSocket.Connect(argv[1],atoi(argv[2]));
    if (iRet != 0)
    {
        printf("Connect error!\n");
        return -1;
    }

    char buff[BUFF_LENGTH] = {0};

    PBMsgHead Msghead;
    MsgReqGMPlayer stReq;
    MsgAnsGMPlayer stAns;

    int iDataLength = 0;
    int iSendlen = 0;

    iRet = DoReqHeadBody(Msghead, stReq, argc, argv);
    if (iRet)
    {
        printf("DoReqHeadBody error!\n");
        return iRet;
    }

    iRet = Encode(Msghead, stReq, buff, iDataLength);
    if (iRet)
    {
        printf("Encode error!\n");
        return -1;
    }

    iRet = sSocket.SendEx(buff, iDataLength, iSendlen);
    if (iRet != 0)
    {
        printf("SendEx error!\n");
        return -1;
    }

    sSocket.Recv(buff, BUFF_LENGTH, iSendlen);
    
    iRet = Decode(Msghead, stAns, buff, iDataLength);
    if (iRet)
    {
        printf("Decode error!\n");
        return -1;
    }

    iRet = OutputMsg(Msghead, stAns);
    if (iRet)
    {
        printf("OutputMsg error!\n");
        return -1;
    }

    return 0;
}

